﻿#region Using

using System;
using System.Collections.Generic;
using System.Linq;
using Vk.Methods.Common;
using Vk.Methods.Notes;
using Vk.Methods.Photos;
using Vk.Methods.Wall;

#endregion

namespace Vk.Methods.News
{
    /// <summary>
    ///     Новость
    /// </summary>
    public class NewsEntity : BaseNewsEntity
    {
        /// <summary>
        ///     Возвращается, если пользователь может удалить новость, всегда содержит true
        /// </summary>
        public bool? CanDelete { get; set; }

        /// <summary>
        ///     Содержит true, если текущий пользователь может редактировать запись
        /// </summary>
        public bool? CanEdit { get; set; }

        /// <summary>
        ///     Массив, содержащий историю репостов для записи. Возвращается только в том случае, если запись является репостом.
        ///     Каждый из объектов массива, в свою очередь, является объектом-записью стандартного формата
        /// </summary>
        public List<WallPost> CopyHistory { get; set; }

        /// <summary>
        ///     Друзья
        /// </summary>
        public ListCount<int> Friends { get; set; }

        /// <summary>
        ///     Заметки
        /// </summary>
        public ListCount<Note> Notes { get; set; }

        /// <summary>
        ///     Фотографии
        /// </summary>
        public ListCount<Photo> Photos { get; set; }

        /// <summary>
        ///     Метки на фотографиях
        /// </summary>
        public ListCount<Photo> PhotoTags { get; set; }

        /// <summary>
        ///     Находится в записях со стен и содержит идентификатор записи на стене владельца
        /// </summary>
        public int? PostId { get; set; }

        /// <summary>
        ///     Идентификатор источника новости (положительный — новость пользователя, отрицательный — новость группы)
        /// </summary>
        public int? SourceId { get; set; }

        /// <summary>
        ///     Тип списка новости
        /// </summary>
        public NewsType Type { get; set; }

        public NewsEntity(ApiNode node) : base(node)
        {
            var typeEnum = node.Enum<NewsType>("type");
            if (typeEnum != null)
            {
                Type = (NewsType) typeEnum;
            }

            SourceId = node.Int("source_id");
            PostId = node.Int("post_id");
            CanEdit = node.Bool("can_edit");
            CanDelete = node.Bool("can_delete");

            var history = node.SelectNode("copy_history");
            if (history != null && history.ChildNodes.Any())
            {
                CopyHistory = history.ChildNodes.Select(x => new WallPost(x)).ToList();
            }

            if (Type == NewsType.Photo | Type == NewsType.WallPhoto)
            {
                var photoNodes =
                    node.SelectNode("photos/items")
                        .ChildNodes;
                if (photoNodes.Any())
                {
                    Photos = new ListCount<Photo>(node.Int("photos/count").Value,
                                                  photoNodes.Select(x => new Photo(x)).ToList());
                }
            }
            switch (Type)
            {
                case NewsType.PhotoTag:
                    var photoTagNodes =
                        node.SelectNode("photo_tags/items")
                            .ChildNodes;
                    if (photoTagNodes.Any())
                    {
                        PhotoTags = new ListCount<Photo>(node.Int("photo_tags/count").Value,
                                                         photoTagNodes.Select(x => new Photo(x)).ToList());
                    }
                    break;
                case NewsType.Note:
                    var notesNodes =
                        node.SelectNode("notes/items")
                            .ChildNodes;
                    if (notesNodes.Any())
                    {
                        Notes = new ListCount<Note>(node.Int("notes/count").Value,
                                                    notesNodes.Select(x => new Note(x)).ToList());
                    }
                    break;
                case NewsType.Friend:
                    var friendsNodes =
                        node.SelectNode("friends/items")
                            .ChildNodes;
                    if (friendsNodes.Any())
                    {
                        Friends = new ListCount<int>(node.Int("friends/count").Value,
                                                     friendsNodes.Select(x => x.Int())
                                                                 .Where(x => x.HasValue)
                                                                 .Select(x => x.Value)
                                                                 .ToList());
                    }
                    break;
                case NewsType.Post:
                    break;
                case NewsType.Photo:
                    break;
                case NewsType.WallPhoto:
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }

    /// <summary>
    ///     Базовая сущность новости
    /// </summary>
    public class BaseNewsEntity : BaseEntity
    {
        /// <summary>
        ///     Находится в записях со стен и содержит массив объектов, которые прикреплены к текущей новости (фотография, ссылка и
        ///     т.п.)
        /// </summary>
        public List<WallAttachment> Attachments { get; set; }

        /// <summary>
        ///     Список комментариев к записи в количестве, указанном в методе News.GetComments()
        /// </summary>
        public List<Comment> Comments { get; set; }

        /// <summary>
        ///     Находится в записях со стен и содержит информацию о комментариях к записи
        /// </summary>
        public CommentsInfo CommentsInfo { get; set; }

        /// <summary>
        ///     Находится в записях со стен, если сообщение является копией сообщения с чужой стены, и содержит идентификатор
        ///     владельца стены, у которого было скопировано сообщение
        /// </summary>
        public int? CopyOwnerID { get; set; }

        /// <summary>
        ///     Находится в записях со стен, если сообщение является копией сообщения с чужой стены, и содержит дату скопированного
        ///     сообщения
        /// </summary>
        public DateTime? CopyPostDate { get; set; }

        /// <summary>
        ///     Находится в записях со стен, если сообщение является копией сообщения с чужой стены, и содержит идентификатор
        ///     скопированного сообщения на стене его владельца
        /// </summary>
        public int? CopyPostID { get; set; }

        /// <summary>
        ///     Время публикации новости
        /// </summary>
        public DateTime? Date { get; set; }

        /// <summary>
        ///     Идентификатор автора записи
        /// </summary>
        /// <remarks>Для метода News.Search</remarks>
        public int? FromId { get; set; }

        /// <summary>
        ///     Находится в записях со стен, в которых имеется информация о местоположении, содержит поля
        /// </summary>
        public GeoInfo Geo { get; set; }

        /// <summary>
        ///     Находится в записях со стен и содержит информацию о числе людей, которым понравилась данная запись
        /// </summary>
        public LikesInfo LikesInfo { get; set; }

        /// <summary>
        ///     Находится в записях со стен, содержит тип новости (post или copy)
        /// </summary>
        public string PostType { get; set; }

        /// <summary>
        ///     Находится в записях со стен и содержит информацию о числе людей, которые скопировали данную запись на свою страницу
        /// </summary>
        public RepostsInfo RepostsInfo { get; set; }

        /// <summary>
        ///     Находится в записях со стен и содержит текст записи
        /// </summary>
        public string Text { get; set; }

        public BaseNewsEntity(ApiNode node)
        {
            PostType = node.String("post_type");
            CopyOwnerID = node.Int("copy_owner_id");
            CopyPostID = node.Int("copy_post_id");
            CopyPostDate = node.DateTime("copy_post_date");
            Date = node.DateTime("date");
            Text = node.String("text");
            FromId = node.Int("from_id");

            CommentsInfo = new CommentsInfo(node.SelectNode("comments"));
            LikesInfo = new LikesInfo(node.SelectNode("likes"));
            RepostsInfo = new RepostsInfo(node.SelectNode("reposts"));
            Geo = new GeoInfo(node.SelectNode("geo"));

            var attachments = node.SelectNode("attachments");
            if (attachments != null)
            {
                Attachments = new List<WallAttachment>();
                foreach (var attachmentNode in
                    attachments.ChildNodes)
                    Attachments.Add(new WallAttachment(attachmentNode));
            }

            var comments = node.SelectNodes("comments/list/*");
            if (comments.Any())
            {
                Comments = comments.Select(x => new Comment(x)).ToList();
            }
        }
    }
}